package com.lit.common.util;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;

import java.util.HashMap;
import java.util.Map;

public class Springs {

    private static final String APPLICATION_CONTEXT_KEY = "APPLICATION_CONTEXT_MAP";

    // Spring应用上下文环境
    private final static Map<String, ApplicationContext> APPLICATION_CONTEXT_MAP = new HashMap<>();

    /**
     * @return ApplicationContext
     */
    public static ApplicationContext getApplicationContextMap() {
        return APPLICATION_CONTEXT_MAP.get(APPLICATION_CONTEXT_KEY);
    }

    /**
     * 实现ApplicationContextAware接口的回调方法，设置上下文环境
     *
     * @param applicationContext spring上下文
     */
    public void setApplicationContext(ApplicationContext applicationContext) {
        Springs.APPLICATION_CONTEXT_MAP.put(APPLICATION_CONTEXT_KEY, applicationContext);
    }

    public static <T> T getBean(Class<T> baseType) {
        try {
            return getApplicationContextMap().getBean(baseType);
        } catch (Exception e) {
            return null;
        }

    }

    public static <T> Map<String, T> getBeansOfType(Class<T> baseType) {
        try {
            return getApplicationContextMap().getBeansOfType(baseType);
        } catch (Exception e) {
            return new HashMap<>();
        }
    }

    /**
     * 注册bean
     *
     * @param beanId    所注册bean的id
     * @param className bean的className，
     *                  三种获取方式：1、直接书写，如：com.mvc.entity.User
     *                  2、User.class.getName
     *                  3.user.getClass().getName()
     */
    public static void registerBean(String beanId, String className) {
        ConfigurableApplicationContext configurableContext = (ConfigurableApplicationContext) getApplicationContextMap();
        BeanDefinitionRegistry beanDefinitionRegistry = (BeanDefinitionRegistry) configurableContext.getBeanFactory();
        BeanDefinitionBuilder beanDefinitionBuilder =
                BeanDefinitionBuilder.genericBeanDefinition(className);
        BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        beanDefinitionRegistry.registerBeanDefinition(beanId, beanDefinition);
    }

    /**
     * 注册bean
     *
     * @param beanId 所注册bean的id
     * @param classZ bean的class
     */
    public static void registerBean(String beanId, Class classZ) {
        registerBean(beanId, classZ.getName());
    }

    public static void registerBean(String beanId, Object object) {
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) Springs.getApplicationContextMap().getAutowireCapableBeanFactory();
        beanFactory.registerBeanDefinition(beanId, beanDefinition(object));
    }


    public static <T> T getBean(String beanId, Class<T> classZ) {
        ConfigurableApplicationContext configurableContext = (ConfigurableApplicationContext) getApplicationContextMap();
        try {
            return configurableContext.getBean(beanId, classZ);
        } catch (Exception e) {
            return null;
        }

    }

    /**
     * 注册bean
     *
     * @param classZ bean的class
     */
    public static void registerBean(Class classZ) {
        registerBean(classZ.getSimpleName(), classZ.getName());
    }


    public static void autowireBean(Object bean) {
        getApplicationContextMap().getAutowireCapableBeanFactory().autowireBean(bean);
    }

    public static Object getBean(Object bean) {
        return bean;
    }

    private static BeanDefinition beanDefinition(Object bean) {
        RootBeanDefinition beanDefinition = new RootBeanDefinition();
        beanDefinition.setBeanClass(Springs.class);
        beanDefinition.setFactoryMethodName("getBean");
        ConstructorArgumentValues constructorArguments = new ConstructorArgumentValues();
        constructorArguments.addGenericArgumentValue(bean);
        beanDefinition.setConstructorArgumentValues(constructorArguments);
        return beanDefinition;
    }
}
